package com.ilearn.iodata.iolingo.service.processor.core.api;

import com.ilearn.iodata.iolingo.service.GetCollectionService;
import com.ilearn.iodata.iolingo.service.processor.GenericODataRequestProcessor;
import com.ilearn.iodata.iolingo.service.provider.GenericEdmProvider;
import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider;
import org.apache.olingo.commons.api.ex.ODataException;
import org.apache.olingo.server.api.*;
import org.apache.olingo.server.api.debug.DebugInformation;
import org.apache.olingo.server.api.debug.DebugSupport;
import org.apache.olingo.server.api.debug.RuntimeMeasurement;

import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import java.util.List;

import static com.ilearn.iodata.iolingo.utils.UrlInit.createODataRequest;

public class GenericODataGetHandler {
    final String namespace;
    private final GenericODataContextImpl context;
    final DataSource ds;
    final OData odata;
    private GetCollectionService getCollectionService;
    private GenericEdmProvider edmProvider;
    /**
     * The split.
     */
    private int split = 0;

    public GenericODataGetHandler(final String pUnit, GetCollectionService getCollectionService, GenericEdmProvider genericEdmProvider) throws ODataException {
        this.namespace = pUnit;
        this.ds = null;
        this.context = new GenericODataContextImpl(this);
        this.odata = OData.newInstance();
        this.getCollectionService = getCollectionService;
        this.edmProvider = genericEdmProvider;
    }

    public GenericODataGetHandler(final String pUnit, final DataSource ds, GetCollectionService getCollectionService, GenericEdmProvider genericEdmProvider) throws ODataException {
        super();
        this.namespace = pUnit;
        this.ds = ds;
        this.context = new GenericODataContextImpl(this);
        this.odata = OData.newInstance();
        this.getCollectionService = getCollectionService;
        this.edmProvider = genericEdmProvider;
    }

    public GenericODataGetContext getGenericODataContext() {
        return context;
    }


    public GenericEdmProvider getEdmProvider() {
        return edmProvider;
    }

    @SuppressWarnings("unchecked")
    public ODataResponse process(final HttpServletRequest request)
            throws ODataException {


        ODataRequest oDataRequest = createODataRequest(request, split);




        GenericEdmProvider edmProvider = context.getEdmProvider();

        ServiceMetadata edm = odata.createServiceMetadata(edmProvider, edmProvider.getReferences());

        final ODataHttpHandler handler = odata.createHandler(edm);
        handler.register(new GenericODataRequestProcessor(context, getCollectionService));
        //handler.register(new GenericEntityCollectionProcessor());
        //handler.register(new GenericEntityProcessor());
        //handler.register(new GenericEntityCollectionProcessor());
        //handler.register(context.getEdmProvider().getServiceDocument());


        /*String oDataReqStr = JSON.toJSONString(oDataRequest);

        System.out.println("oDataReqStr:" + oDataReqStr);*/

        ODataResponse oDataResponse = handler.process(oDataRequest);

        return oDataResponse;
    }

    class GenericDebugSupportWrapper implements DebugSupport {

        private final DebugSupport debugSupport;
        private GenericServiceDebugger debugger;

        public GenericDebugSupportWrapper(final DebugSupport debugSupport) {
            super();
            this.debugSupport = debugSupport;
        }

        /*
         * (non-Javadoc)
         *
         * @see org.apache.olingo.server.api.debug.DebugSupport#createDebugResponse(java.lang.String,
         * org.apache.olingo.server.api.debug.DebugInformation)
         */
        @Override
        public ODataResponse createDebugResponse(final String debugFormat, final DebugInformation debugInfo) {
            joinRuntimeInfo(debugInfo);
            return debugSupport.createDebugResponse(debugFormat, debugInfo);
        }

        /*
         * (non-Javadoc)
         *
         * @see org.apache.olingo.server.api.debug.DebugSupport#init(org.apache.olingo.server.api.OData)
         */
        @Override
        public void init(final OData odata) {
            debugSupport.init(odata);
        }

        /*
         * (non-Javadoc)
         *
         * @see org.apache.olingo.server.api.debug.DebugSupport#isUserAuthorized()
         */
        @Override
        public boolean isUserAuthorized() {
            return debugSupport.isUserAuthorized();
        }

        void setDebugger(final GenericServiceDebugger debugger) {
            this.debugger = debugger;
        }

        private void joinRuntimeInfo(final DebugInformation debugInfo) {
            // Olingo create a tree for runtime measurement in DebugTabRuntime.add(final RuntimeMeasurement
            // runtimeMeasurement). The current algorithm (V4.3.0) not working well for batch requests if the own runtime info
            // is just appended (addAll), so insert sorted:
            final List<RuntimeMeasurement> olingoInfo = debugInfo.getRuntimeInformation();
            int startIndex = 0;
            for (RuntimeMeasurement m : debugger.getRuntimeInformation()) {
                for (; startIndex < olingoInfo.size(); startIndex++) {
                    if (olingoInfo.get(startIndex).getTimeStarted() > m.getTimeStarted()) {
                        break;
                    }
                }
                olingoInfo.add(startIndex, m);
                startIndex += 1;
            }
        }
    }

}
